﻿#include "application.h"

#include <QDesktopServices>
#include <QtCore/QBuffer>
#include <QtCore/QDir>
#include <QtCore/QLibraryInfo>
#include <QtCore/QSettings>
#include <QtCore/QTextStream>
#include <QtCore/QTranslator>
#include <QtCore/QReadWriteLock>
#include <QtCore/QCommandLineParser>

#include <QDesktopServices>
#include <QFileOpenEvent>

#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QNetworkProxy>
#include <QStyle>
#include <QStyleFactory>
#include <QtCore/QDebug>
#include <QMessageBox>
#include <QStandardPaths>
#include <QMetaMethod>
#include <QMetaObject>
#include <QTimer>
#include <QTextBrowser>

#include <stdio.h>
#include <stdlib.h>

#ifdef Q_OS_WIN
    #include "shlwapi.h"
    #include "shellapi.h"
#endif
#define DATADEFAULNAME QStringLiteral("投料机数据")
#define APPDEFAULNAME QStringLiteral("投料软件")

QMap<QString, QIcon> Application::s_hostIcons;
bool Application::s_resetOnQuit = false;
bool Application::s_portableRunMode = false;
bool Application::s_startResizeOnMouseweelClick = true;
QReadWriteLock lockIcons;

QTextBrowser *Application::textbrowser = 0;


static void showHelp(QCommandLineParser &parser, const QString errorMessage = QString())
{
    QString text;
    QTextStream str(&text);
    str << "<html><head/><body>";
    if (!errorMessage.isEmpty())
        str << errorMessage;
    str << "<pre>" << parser.helpText() << "</pre></body></html>";
    QMessageBox box(errorMessage.isEmpty() ? QMessageBox::Information : QMessageBox::Warning,
        QGuiApplication::applicationDisplayName(), text, QMessageBox::Ok);
    box.setTextInteractionFlags(Qt::TextBrowserInteraction);
    box.exec();
}

int Application::getApplicationBuild()
{
    return 108; // Current Build
}

Application::Application(int &argc, char **argv)
    : QApplication(argc, argv)
    , m_localServer(0)
    , quiting(false)
    , m_initialUrl(QString())
    , m_correctlyInitialized(false)
{
    QCoreApplication::setOrganizationName(QLatin1String("YanboOrg"));
    QCoreApplication::setApplicationName(QLatin1String("FishSoftware"));
    QCoreApplication::setApplicationVersion(QLatin1String("2.0"));

    //remove old data.
    QSettings set_remove;
    set_remove.beginGroup("general");
    if(set_remove.value("IsOldVersion",true).toBool()){
        QString str_cfgdir = QStandardPaths::writableLocation(QStandardPaths::DataLocation)+QDir::separator()+"config";
        QDir dir_cfg(str_cfgdir);
        if(dir_cfg.exists()){
            dir_cfg.removeRecursively();
        }
//        dir_cfg.setPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)+QDir::separator()+"data");
//        if(dir_cfg.exists()){
//            dir_cfg.removeRecursively();
//        }
        set_remove.setValue("IsOldVersion",false);
    }

    QCommandLineParser commandLineParser;
    commandLineParser.addPositionalArgument(QStringLiteral("url"),
        QStringLiteral("The url to be loaded in the window."));

    if (!commandLineParser.parse(QCoreApplication::arguments())) {
        showHelp(commandLineParser, QStringLiteral("<p>Invalid argument</p>"));
        return;
    }

    QStringList args = commandLineParser.positionalArguments();
    if (args.count() > 1) {
        showHelp(commandLineParser, QStringLiteral("<p>Too many arguments.</p>"));
        return;
    } else if (args.count() == 1) {
        m_initialUrl = args.at(0);
    }
    if (!m_initialUrl.isEmpty() && !QUrl::fromUserInput(m_initialUrl).isValid()) {
        showHelp(commandLineParser, QString("<p>%1 is not a valid url</p>").arg(m_initialUrl));
        return;
    }

    m_correctlyInitialized = true;

    QString serverName = QCoreApplication::applicationName();
    
    definePortableRunMode();

    QLocalSocket socket;//set the single application.
    socket.connectToServer(serverName);
    if (socket.waitForConnected(500))
    {
        QTextStream stream(&socket);
        QStringList args = QCoreApplication::arguments();
        if (args.count() > 1)
            stream << args.last();
        else
            stream << QString();
        stream.flush();
        socket.waitForBytesWritten();
        return;
    }


    QApplication::setQuitOnLastWindowClosed(true);

    m_localServer = new QLocalServer(this);

    connect(m_localServer, SIGNAL(newConnection()),this, SLOT(newLocalSocketConnection()));

    if (!m_localServer->listen(serverName)) {
        if (m_localServer->serverError() == QAbstractSocket::AddressInUseError
            && QFile::exists(m_localServer->serverName())) {
            QFile::remove(m_localServer->serverName());
            m_localServer->listen(serverName);
        }
    }

    QDesktopServices::setUrlHandler(QLatin1String("http"), this, "openUrl");

    CheckSetTranslator();

    setStyle(QStyleFactory::create("Fusion"));

    QTimer::singleShot(0, this, SLOT(postLaunch()));

    if(!textbrowser)
        textbrowser = new QTextBrowser();
    textbrowser->setAttribute(Qt::WA_DeleteOnClose);
    QSettings setting;
    setting.beginGroup("general");
    bool isshow = setting.value("IsShowDebug",false).toBool();
    setting.endGroup();

    if(textbrowser->isHidden() && isshow)
        textbrowser->show();
}

void Application::CheckSetTranslator()
{
//    QStringList args = QCoreApplication::arguments();

    QString langName = QLocale::system().name();
    QStringList list;
    list << ":/res/lang/qtbasesubset_%1.qm"<<
            ":/res/lang/FishProject_%2.qm";
    foreach(QString fileName,list){
        QString langFile =  fileName.arg(langName);
        QFileInfo fileInfo(langFile);
        if(fileInfo.exists()){
            QTranslator *translator = new QTranslator(qApp);
            translator->load(langFile);
            qApp->installTranslator(translator);
        }
    }
}

void Application::appendDebugMsg(const QString &str)
{
    if(textbrowser)
        textbrowser->append(str);
}

bool removeDir(const QString &dirName)
{
    bool result;
    QDir dir(dirName);

    if (dir.exists()) {
        Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden  | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
            if (info.isDir()) {
                result = removeDir(info.absoluteFilePath());
            }
            else {
                result = QFile::remove(info.absoluteFilePath());
            }

            if (!result) {
                return result;
            }
        }
        result = dir.rmdir(dirName);
    }
    return result;
}

void Application::definePortableRunMode()
{
    //create by vacant
    //Note:if the application is not setup to this Machine,that means the app is not use installer tools.
    s_portableRunMode = !QFile::exists(QCoreApplication::applicationDirPath() + "/unins000.exe");
    if (s_portableRunMode)
    {
        QSettings::setDefaultFormat(QSettings::NativeFormat);//you can switch to IniFormat to save it in the Ini file.
        QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, QStandardPaths::writableLocation(QStandardPaths::DataLocation));
        bool is_writable = true;
        {
            QSettings settings;
            settings.beginGroup(QLatin1String("general"));
            is_writable = settings.isWritable();
            settings.setValue(QLatin1String("settings_writable"), true);
        }
        {
            QSettings settings;
            settings.beginGroup(QLatin1String("general"));
            bool tested_ok = settings.value(QLatin1String("settings_writable"), false).toBool();
            // just removing this test value
            if (is_writable)
                settings.remove("settings_writable");
            if (!tested_ok || is_writable)
            {
                // Copy settings from base template to temporary storage
                QDir temp_dir(QDir::temp());
                bool res = temp_dir.mkpath(settings.organizationName());
                res = temp_dir.cd(settings.organizationName());
                QString path = temp_dir.absolutePath() + QDir::separator() + settings.applicationName();
                res = QFile::copy(  settings.fileName(), QDir::toNativeSeparators(path) + ".ini" );
                // Change path to settings to the temp storage
                QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, QDir::temp().tempPath());
            }
        }
    }
}

Application::~Application()
{
    QReadLocker locker(&lockIcons);
    s_hostIcons.clear();

    quiting = true;

    if(textbrowser)
        delete textbrowser;

    if (true)
    {
#ifdef Q_OS_WIN
        HKEY hKey;

        wchar_t key[256];
        wcscpy(key, L"Software");
        if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, DELETE, &hKey))
        {
            RegDeleteKey(hKey, (LPCWSTR)organizationName().utf16());
            RegCloseKey(hKey);
        }
#endif

    }
//    qDeleteAll();
}

Application *Application::instance()
{
    return (static_cast<Application *>(QCoreApplication::instance()));
}

/*!
    Any actions that can be delayed until the window is visible
 */
void Application::postLaunch()
{
    QString directory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
    if (directory.isEmpty())
        directory = QDir::homePath() + QLatin1String("/.") + QCoreApplication::applicationName();
    setWindowIcon(QIcon(":/res/global/app.png"));
//    setWindowIcon(QIcon(QApplication::style()->standardIcon(QStyle::SP_FileDialogInfoView)));

    loadSettings();

    // newMainWindow() needs to be called in main() for this to happen
}

extern QString DefaultAppStyle();

void Application::loadSettings()
{
    QSettings settings;
    if(!settings.value("general/changedirpath",false).toBool()){
        settings.setValue("general/DefaultSaveDir",QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/data/");
        settings.setValue("general/changedirpath",true);
    }

    QString pathDir = settings.value("general/DefaultSaveDir",QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/data/").toString();

qDebug()<<"set the data path."<<pathDir;

    settings.setValue("general/DefaultSaveDir",pathDir);
    QDir dir(pathDir);
    if(!dir.exists())
        dir.mkpath(pathDir);
    QFile fileLink(pathDir);
    QString linkPath_Data = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + QString("/%1.lnk").arg(DATADEFAULNAME);
    if(!QFile::exists(linkPath_Data))
//        QFile::remove(linkPath_Data);//not delete.
    fileLink.link(linkPath_Data);//Set the Link to the Data Path.

    //Set the Link Path to the App.
    fileLink.setFileName(QApplication::applicationFilePath());
//    QFileInfo fileInfo(QApplication::applicationFilePath());
    linkPath_Data = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + QString("/%1.lnk").arg(/*fileInfo.baseName()*/APPDEFAULNAME);
    if(!QFile::exists(linkPath_Data))
        fileLink.link(linkPath_Data);
}

void Application::clean()
{
    // cleanup any deleted main windows first
}

static const qint32 ApplicationMagic = 0xec;


bool Application::isTheOnly() const
{
    return (m_localServer != 0);
}

bool Application::isCorrectlyInitialized() const
{
    return m_correctlyInitialized;
}

void Application::installTranslator(const QString &name)
{
    QTranslator *translator = new QTranslator(this);
    translator->load(name, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    QApplication::installTranslator(translator);
}

//bool Application::notify(QObject *obj, QEvent *event)
//{
//    if(event->type() == QEvent::MetaCall){
//        qDebug()<<"problem."<<event->type();
//        const QMetaObject* metaObject = obj->metaObject();
//        QStringList methods;
//        for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
//            methods << QString::fromLatin1(metaObject->method(i).methodSignature());        //return false;
//        qDebug()<<"methods:"<<obj->objectName()<<methods;
//    }

//    qDebug()<<__LINE__<<QDateTime::currentDateTime().toString()<<__FUNCTION__<<
//              event->type()<<
//              obj->objectName();
//    return QApplication::notify(obj,event);
//}

void Application::newLocalSocketConnection()
{
    QLocalSocket *socket = m_localServer->nextPendingConnection();
    qDebug()<<"waitForConnected"<<m_localServer->isListening()<<socket;

    if (!socket)
        return;
    socket->waitForReadyRead(1000);
    QTextStream stream(socket);
    QString url;
    stream >> url;
    if (!url.isEmpty()) {
        QSettings settings;
        settings.beginGroup(QLatin1String("general"));
        int openLinksIn = settings.value(QLatin1String("openLinksIn"), 0).toInt();
        qDebug()<<"openLinksIn:"<<openLinksIn;
        settings.endGroup();
    }
    delete socket;
    qDebug()<<"openLinksIn111:";
}

//QIcon Application::icon(const QUrl &, const WebView */*webView*/) const//ToDo..cant get web icon...
//{
////    if (url.scheme() == QLatin1String("https"))
////        return QIcon(QLatin1String(":secureicon.png"));

//////    if (QWebSettings::iconDatabasePath().isEmpty())
//////        QWebSettings::setIconDatabasePath(dataLocation());

////    QIcon icon;
////    if (webView)
////        icon = webView->icon();
////    else
////        icon = QWebSettings::iconForUrl(url);

////    if (!icon.isNull())
////        return icon.pixmap(16, 16);

//////    return QIcon(QLatin1String(":/webkit/resources/urlIcon.png"));
//    return QIcon(QLatin1String(":/defaulticon.png"));
//}

void Application::closeMainWindows()
{

}
